﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace NielsRask.K242.Core
{
	public class Fleet
	{
		public PointF Position { get; private set; }
		public PointF Direction { get; private set; }	// enhedsvektor!
		public float Velocity { get; private set; }	// hastighed pr turn - skal justeres hen af vejen ...
		public AI.General General { get; private set; }
		public AI.Emperor Emperor { get { return this.General.Emperor; } }
		public float SensorRange = 100f;
		public ShipList Ships { get; private set; }
		public Queue<PointF> Waypoints { get; private set; }
		public Queue<FleetOrder> Orders { get; private set; }
		public bool CanColonize = false;

		public Fleet(AI.General general, PointF position)
		{
			Ships = new ShipList();
			Position = position;
			General = general;
			Waypoints = new Queue<PointF>();
			Orders = new Queue<FleetOrder>();
			Velocity = 15;
		}

		public Fleet(AI.General general, PointF position, Ship ship)
			: this(general, position)
		{
			AddShip( ship );
		}

		public void AddShip( Ship ship )
		{
			Ships.Add( ship );
			RecalculateFleetStats();
		}

		private void RecalculateFleetStats()
		{
			Velocity = Ships[ 0 ].Speed;
			SensorRange = Ships[ 0 ].SensorRange;
			CanColonize = Ships[0].CanColonize;
			for ( int i = 0; i < Ships.Count; i++ )
			{
				if ( Ships[ i ].Speed < Velocity )
					Velocity = Ships[ i ].Speed;

				if ( Ships[ i ].SensorRange > SensorRange )
					SensorRange = Ships[ i ].SensorRange;

				if ( Ships[ i ].CanColonize )
					CanColonize = true;
			}
		}

		public delegate void AsteroidDiscoveredHandler( Asteroid asteroid );
		public event AsteroidDiscoveredHandler AsteroidDiscovered;
		public void OnAsteroidDiscovered(Asteroid asteroid)
		{
			if (AsteroidDiscovered != null)
				AsteroidDiscovered(asteroid);
		}

		public delegate void FleetDiscoveredHandler(Fleet fleet);
		public event FleetDiscoveredHandler FleetDiscovered;
		public void OnFleetDiscovered(Fleet fleet)
		{
			if (FleetDiscovered != null)
				FleetDiscovered(fleet);
		}

		public void UpdatePosition() 
		{
			if (Orders.Count > 0) 
			{
				FleetOrder order = Orders.Peek();
				var moveOrder = order as MoveOrder;
				if (moveOrder != null)
				{
					if (MoveTowards(moveOrder.Position))
						Orders.Dequeue();	// ordren er gennemført
				}
				var attackOrder = order as AttackOrder;
				if ( attackOrder != null )
				{
					// er vi indenfor range?
					Attack( attackOrder.Target );

					Orders.Dequeue();	// ordren er gennemført - eller er flåden død?
				}
				var colonizeOrder = order as ColonizeOrder;
				if ( colonizeOrder != null )
				{
					// er vi indenfor range?
					Colonize( colonizeOrder.Target );

					Orders.Dequeue();	// ordren er gennemført - eller er flåden død?
					//TODO: fjern et colonyship fra flåden!
				}
			}
		}

		// false mens vi ikke er fremme
		public bool MoveTowards(PointF target)
		{
			//PointF dir = new PointF(Position.X - target.X, Position.Y - target.Y);
			PointF dir = new PointF(target.X - Position.X, target.Y - Position.Y);
			float scale = (float)Math.Sqrt(dir.X * dir.X + dir.Y * dir.Y);

			Direction = new PointF(dir.X / scale, dir.Y / scale);

			if (scale <= Velocity)	// lille overshoot her - evt kunne man sænke hastigheden når vores bevægelsesmdoel er lidt mere moden
			{
				return true;
			}

			float newX = Position.X + (Direction.X * Velocity);
			float newY = Position.Y + (Direction.Y * Velocity);
			Position = new PointF(newX, newY);

			return false;
		}

		public void Attack(Asteroid asteroid)
		{
			Sector.ResolveCombat(this, asteroid.Colony);
		}

		public void Colonize( Asteroid asteroid )
		{
			if ( asteroid.EmperorKnowledge[ Emperor ] == EmperorInfo.Uninhabited )
			{
				Emperor.Colonize( asteroid );
			}
		}
	}

	public abstract class FleetOrder
	{
	}

	public class MoveOrder : FleetOrder
	{
		public PointF Position {get; private set;}
		
		public MoveOrder(PointF position)
		{
			Position = position;
		}
	}

	public class AttackOrder : FleetOrder
	{
		public Asteroid Target { get; private set; }
		public PointF Position { get { return Target.Position; } }
		public AttackOrder( Asteroid asteroid )
		{
			Target = asteroid;
		}

	}
	public class ColonizeOrder : FleetOrder
	{
		public Asteroid Target { get; private set; }
		public PointF Position { get { return Target.Position; } }
		public ColonizeOrder( Asteroid asteroid )
		{
			Target = asteroid;
		}

	}
	//joinfleet
}
